package com.ugold.web.aspect;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSONObject;
import com.ugold.web.common.Result;
import com.ugold.web.common.exception.BizException;
import com.ugold.web.common.exception.ErrorEnum;
import com.ugold.web.common.exception.IntegrationException;
import com.ugold.web.common.util.HttpUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * 服务请求拦截
 * <p/>
 *
 * @author jim
 * @date 16/10/12
 */
@Aspect
@Component
@Slf4j
public class ServiceRequestAspect {

	@Value("#{'${allow.domain.name}'.split(',')}")
	private List<String> allowDomainName;

	@Pointcut("execution(public * com.ugold.web.controller.*.*(..))")
	private void allMethod() {
	}

	@Around("allMethod()")
	public Object doAround(ProceedingJoinPoint call) throws Throwable {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
				.getRequest();
		String api = request.getRequestURI();
		StringBuffer requestURL = request.getRequestURL();
		String ip = HttpUtil.getIpAddress(request);
		log.info("IP={},API={},requestURL={}", ip, api, requestURL);

		if (!this.isInAllowDomain(requestURL.toString())) {
			log.warn("不被允许访问的域名请求，requestURL={}", requestURL);
			return Result.buildFailureResult(ErrorEnum.ERROR_NO_AUTHORITY.getErrorCode(), "请求域名禁止访问");
		}

		Long startTime = System.currentTimeMillis();
		boolean requestResult = false;
		try {
			// 处理请求
			Object object = call.proceed();
			log.info("[IP={}] [RESULT={}]", ip, JSONObject.toJSONString(object));
			return object;
		} catch (IntegrationException e) {
			log.warn("IntegrationException服务请求处理异常，异常信息：" + e.getErrorMessage(), e);
			Result<?> buildErrorResult = null;
			if (StringUtils.isNotEmpty(e.getErrorMessage())) {
				buildErrorResult = Result.buildFailureResult(e.getErrorCode(), e.getErrorMessage());
			} else {
				buildErrorResult = Result.buildFailureResult(ErrorEnum.ERROR_SERVICE.getErrorCode(),
						ErrorEnum.ERROR_SERVICE.getErrorMessage());
			}
			log.warn("IntegrationException异常返回JSON:{}", JSONObject.toJSONString(buildErrorResult));
			return buildErrorResult;
		} catch (BizException e) {
			log.warn("BizException服务请求处理异常，异常信息：" + e.getErrorMessage(), e);
			Result<?> buildErrorResult = null;
			if (StringUtils.isNotEmpty(e.getErrorMessage())) {
				buildErrorResult = Result.buildFailureResult(e.getErrorCode(), e.getErrorMessage());
			} else {
				buildErrorResult = Result.buildFailureResult(ErrorEnum.ERROR_SERVICE.getErrorCode(),
						ErrorEnum.ERROR_SERVICE.getErrorMessage());
			}
			log.warn("BizException异常返回JSON:{}", JSONObject.toJSONString(buildErrorResult));
			return buildErrorResult;
		} catch (Exception e) {
			log.error("Exception服务请求处理异常，异常信息：" + e.getMessage(), e);
			log.error("[RESPONSE_ERROR={}]", ErrorEnum.ERROR_SERVICE.toString());
			Result<?> buildErrorResult = Result.buildFailureResult(ErrorEnum.ERROR_SERVICE.getErrorCode());
			log.warn("Exception异常返回JSON:{}", JSONObject.toJSONString(buildErrorResult));
			return buildErrorResult;
		} finally {
			long runTime = System.currentTimeMillis() - startTime;
			log.info("[API={}] [requestResult={}] [runTime={}ms]", api, requestResult, runTime);
			MDC.clear();
		}
	}

	/**
	 * 检查请求域名是否在指定域名内
	 * 
	 * @author dingjian
	 * @date 2019年7月23日下午6:12:09
	 * @param requestURL
	 * @return
	 */
	private boolean isInAllowDomain(String requestURL) {
		if (CollectionUtils.isEmpty(allowDomainName)) {
			return false;
		}
		boolean inDomain = allowDomainName.stream().filter(e -> StringUtils.contains(requestURL, e)).findAny()
				.isPresent();
		return inDomain;
	}
}
